﻿/// <reference path="MicrosoftAjax.js"/>
/// <reference path="MicrosoftAjaxTemplates.js"/>

function createTreeView(element, data, nodeTemplate) {
    /// <summary>Creates a tree view over the tree element. This is not a general purpose tree view.</summary>
    /// <param name="element" domElement="true">The element on which to create the tree.</param>
    /// <param name="data" type="Array">The data that the tree must display.</param>
    /// <param name="nodeTemplate">The template to use for the tree nodes.</param>
    Sys.create.dataView(element, {
        data: data,
        itemTemplate: nodeTemplate,
        command: onCommand,
        itemRendered: function(sender, args) {
            // Set-up the node expansion toggle button
            var toggleButton = args.get(".toggleButton");
            if (Type.isNamespace(args.dataItem)) {
                Sys.UI.DomEvent.addHandler(toggleButton, "click", function(e) {
                    e.preventDefault();
                    return toggleVisibility(this);
                }, true);
            }
            else {
                Sys.UI.DomElement.setVisible(toggleButton, false);
            }
            // Set-up the node itself
            var treeNode = args.get(".treeNode");
            Sys.UI.DomEvent.addHandler(treeNode, "click", function(e) { e.preventDefault(); return false; }, true);
            Sys.setCommand(treeNode, "select");
            treeNode.innerHTML = getSimpleName(args.dataItem.getName());
            // Create the child node DataView
            var childView = args.get("ul");
            createTreeView(childView, getChildren(args.dataItem), nodeTemplate);
        }
    });
}

function getChildren(parent) {
    /// <summary>Creates the list of class and namespace children of a namespace.</summary>
    /// <param name="parent"/>
    /// <returns type="Array"/>
    var children = [];
    for (var name in parent) {
        if (name[0] === '_') continue;
        var child = parent[name];
        if (child.getName && (
            Type.isNamespace(child) ||
            Type.isClass(child))) {

            children.push(child);
        }
    }
    return children.sort(function(a, b) {
        return a.getName() < b.getName() ? -1 : 1;
    });
}

function getMembers(type) {
    /// <summary>Gets the list of members of a type.</summary>
    /// <param name="type" type="Type">The type to explore.</param>
    /// <returns type="Array"/>
    var members = [];
    for (var name in type.prototype) {
        if (name[0] === '_' ||
                    name.startsWith("set_") ||
                    name.startsWith("remove_")) continue;
        members.push((typeof type.prototype[name] !== "function") ?
                        { type: "property", name: name} :
                    name.startsWith("get_") ?
                        { type: "property", name: name.substr(4)} :
                    name.startsWith("add_") ?
                        { type: "event", name: name.substr(4)} :
                        { type: "method", name: name }
                );
    }
    for (name in type) {
        if (name[0] === '_') continue;
        var member = type[name];
        if (typeof member === "function" && !Function.prototype[name]) {
            members.push({ type: "staticMethod", name: name });
        }
    }
    return members.sort(function(a, b) { return a.name < b.name ? -1 : 1; });
}

function getSimpleName(fullName) {
    /// <summary>Extracts the simple name of a type from its fully-qualified name.</summary>
    /// <param name="fullName" type="String"/>
    /// <returns type="String"/>
    return fullName.replace(/.+\.([^\.]+)/i, "$1");
}

function toggleVisibility(element) {
    /// <summary>Toggles the visibility of the child nodes of a tree node.</summary>
    /// <param name="element" domElement="true">The parent node.</param>
    var childList = element.parentNode.getElementsByTagName("ul")[0],
        isClosed = element.innerHTML === "+";
    childList.style.display = isClosed ? "block" : "none";
    element.innerHTML = isClosed ? "-" : "+";
    return false;
}

function onCommand(sender, args) {
    if (args.get_commandName() === "select") {
        var dataItem = sender.findContext(args.get_commandSource()).dataItem;
        var isClass = Type.isClass(dataItem) && !Type.isNamespace(dataItem);
        var childData = (isClass ? getMembers : getChildren)(dataItem),
            namespaceElementsDisplay = isClass ? "none" : "block",
            classElementsDisplay = isClass ? "block" : "none",
            detailsChild = Sys.Application.findComponent("detailsChild");
        detailsChild.onItemRendering = isClass ? onClassMemberRendering : onNamespaceChildRendering;
        detailsChild.set_data(childData);
        Sys.get("#detailsTitle").innerHTML = dataItem.getName();
        Sys.get("#namespacesColumn").style.display =
        Sys.get("#classesColumn").style.display = namespaceElementsDisplay;
        Sys.get("#propertiesColumn").style.display =
        Sys.get("#eventsColumn").style.display =
        Sys.get("#methodsColumn").style.display =
        Sys.get("#staticMethodsColumn").style.display = classElementsDisplay;
        Sys.get("#details").style.display = "block";
    }
}

function onNamespaceChildRendering(args) {
    args.set_itemPlaceholder(
        Type.isClass(args.get_dataItem()) ?
            "#classPlaceHolder" :
            "#namespacePlaceHolder"
    );
}

function onClassMemberRendering(args) {
    var memberType = args.get_dataItem().type;
    args.set_itemPlaceholder("#" + memberType + "PlaceHolder");
}

function onDetailsChildRendered(sender, args) {
    args.get("li").innerHTML = args.dataItem.getName ? args.dataItem.getName() : args.dataItem.name;
}
